#include "HttpConnection.hpp"
#include "LogicSystem.h"
#include "UrlCoding.h"

// DONE:全部改造成asio相关处理，参考链接：https://gitbookcpp.llfc.club/sections/cpp/boost/asio22.html
HttpConnection::HttpConnection(boost::asio::io_context &ioc) : _socket(ioc)
{
}

void HttpConnection::Start()
{
    auto self = shared_from_this();
    // 读数据
    // http::async_read(_socket, _buffer, _request, [self](beast::error_code ec, std::size_t bytes_transferred) {
    //     try
    //     {
    //         if (ec)
    //         { // 出现异常则重新监听
    //             std::cerr << "http read err is " << ec.what() << std::endl;
    //             // 不需要再次Start()来监听请求，因为在CServer中会重新调用Start()
    //             //  self->Start();
    //             return;
    //         }

    //         // 处理请求
    //         boost::ignore_unused(bytes_transferred);
    //         self->HandleReq();
    //         // 启动超时监测
    //         self->CheckDeadline();
    //     }
    //     catch (const std::exception &e)
    //     {
    //         std::cerr << e.what() << '\n';
    //     }
    // });

    // asio处理请求
    _socket.async_read_some(
        boost::asio::buffer(_buffer), [self](boost::system::error_code ec, std::size_t bytes_transferred) {
            try
            {
                if (ec)
                { // 出现异常则重新监听
                    if (ec != boost::asio::error::eof)
                        LOG_ERROR("http read err is {}", ec.what());
                    else
                        LOG_INFO("http connection closed");
                    // 不需要再次Start()来监听请求，因为在CServer已经注册了新的响应连接Handler，该连接将被废弃
                    //  self->Start();
                    return;
                }

                // 查找Content-Length
                std::size_t pos = 0;
                self->_read_len += bytes_transferred;
                std::size_t len = 0;
                std::string tmp(self->_buffer);
                if ((pos = tmp.find("Content-Length: ")) != std::string::npos)
                {
                    pos += 17; // 找到长度的位置
                    std::size_t end = tmp.find("\r\n", pos);
                    len = std::stoi(tmp.substr(pos, end - pos));
                }

                std::size_t total_len = 0;
                if (pos != std::string::npos) // 能找到pos说明有请求体
                {
                    if ((pos = tmp.find("\r\n\r\n")) != std::string::npos) // 判断是否读取完请求头
                    {
                        self->_head_len.store(pos); // 请求头长度

                        total_len = self->_head_len.load() + len;
                        if (self->_read_len.load() < total_len) // 还没读完
                        {
                            // 继续读取
                            self->Start(); // 这里需要重新注册，因为数据还没读取完，需要再次调用async_read_some()
                            return;
                        }
                    }
                }
                else if ((pos = tmp.find("\r\n\r\n")) == std::string::npos) // 还没读完
                {
                    // 继续读取
                    self->Start();
                    return;
                }
                else // 说明没有请求体
                {
                    total_len = pos + 4;
                }

                // LOG_INFO("total_len: " + std::to_string(total_len));
                self->_buffer[total_len] = '\0'; // 加上终止字符，否则将会有一堆乱码

                // 处理请求
                boost::ignore_unused(bytes_transferred);
                self->ReadReq();
                self->HandleReq();
                // 启动超时监测
                self->CheckDeadline();
            }
            catch (const std::exception &e)
            {
                // std::cerr << e.what() << '\n';
                if (ec != boost::asio::error::eof)
                    LOG_ERROR("http read err is {}", ec.what());
                else
                    LOG_INFO("http connection closed");
            }
        });
}

void HttpConnection::ReadReq()
{
    // 从请求中读取数据
    std::string body_str(_buffer);
    LOG_INFO("http read is\n{}", body_str);
    std::string head = body_str.substr(0, body_str.find("\r\n"));
    std::string version;
    unsigned int method;
    std::string target;
    std::string body;
    // 解析请求头
    // 解析请求方法
    std::size_t end = head.find(" "); // 找到第一个空格
    std::string tmp = body_str.substr(0, end);
    if (tmp == "GET")
        method = http_method::get;
    else if (tmp == "POST")
        method = http_method::post;
    head.erase(0, end + 1);
    // 解析请求url
    end = head.find(" ");
    target = head.substr(0, end);
    head.erase(0, end + 1);
    // 解析http版本
    std::size_t pos = head.find("HTTP");
    end = head.find("\r\n", pos);
    version = head.substr(pos + 5, end);

    // 解析请求体
    pos = body_str.find("\r\n\r\n");
    body = body_str.substr(pos + 4);

    _request = Request(method, version, target, body);
}

void HttpConnection::HandleReq()
{
    // 设置版本，在这里使用默认的版本号也就是1.1即可
    _response.version(_request.version());
    // 设置为短链接（HTTP是短链接）
    _response.keep_alive(false);

    // 处理get请求
    if (_request.method() == http_method::get) // 如果是get请求
    {
        PreParseGetParam(); // url预处理，获取请求参数
        // 调用LogicSystem处理get请求
        bool success = LogicSystem::GetInstance()->HandleGetReq(_get_url, shared_from_this());
        // 返回响应
        if (!success)
        {
            HandleNotFound();
        }

        HandleSuccess();
        return;
    }

    // post请求
    if (_request.method() == http_method::post) // 如果是post请求
    {
        bool success = LogicSystem::GetInstance()->HandlePostReq(_request.target(), shared_from_this());
        // 返回响应
        if (!success)
        {
            HandleNotFound();
            return;
        }

        HandleSuccess();
        return;
    }

    // TODO:如果是其他请求。。。
}

void HttpConnection::CheckDeadline()
{
    auto self = shared_from_this();
    _deadline.async_wait([self](beast::error_code ec) {
        if (!ec)
        {
            self->_socket.close(ec);
        }
    });
}


void HttpConnection::WriteResponse()
{
    Handle_Write_Header();
}

void HttpConnection::Handle_Write_Header()
{
    auto self = shared_from_this();
    _socket.async_write_some(
        asio::buffer(_response.getHeader(), _response.getHeaderLen()),
        [self](auto ec, auto bytes_transferred){
            self->_written_header_len += bytes_transferred;
            if (!ec)
            {
                LOG_ERROR("write error!, detail: {}", ec.what());
            }
            if (self->_written_header_len >= self->_response.getHeaderLen())
            {
                LOG_INFO("Write Header Finished");
                // self->_header_sent = true;
                self->Handle_Write_Body();
            }
            else
            {
                self->Handle_Write_Header();
            }
        }
    );
}

void HttpConnection::Handle_Write_Body()
{
    auto self = shared_from_this();
    asio::mutable_buffer m_buffer;
    asio::const_buffer c_buffer;

    std::unique_lock<std::mutex> lk(self->_mtx);
    std::weak_ptr<HttpConnection> weak_self(self);
    //TODO:为什么这里wait(lk)会报错？
    self->_cv.wait(lk, [weak_self](){
        auto ptr = weak_self.lock();
        if (ptr->_response._is_img)
            return ptr->_is_data_ready;
        else return true;
    });

    if (self->_response._is_img)
    {
        // m_buffer = {self->_response.get_img_body(), self->_response.getBodyLen()};
        m_buffer = {self->_response.get_img_body(), 1024};
    }
    else
    {
        // self->_body_buffer.assign(self->_response.getBodyLen(), '\0');
        // c_buffer = asio::buffer(self->_response.get_body_str(), self->_bytes_read);
        m_buffer = asio::buffer(self->_response.get_body_str(), self->_response.getBodyLen());
    }
    
    try
    {
        _socket.async_write_some(
            // self->_response._is_img ? m_buffer : c_buffer,  //根据情况选用不同的buffer
            m_buffer,
            [self](auto ec, std::size_t bytes_transferred){
                // auto self = weak_self.lock();
                // std::unique_lock<std::mutex> lk(self->_mtx);
                // //TODO:为什么这里wait(lk)会报错？
                // std::weak_ptr<HttpConnection> weak_self(self);
                // self->_cv.wait(lk, [weak_self](){
                //     auto ptr = weak_self.lock();
                //     if (ptr->_response._is_img)
                //         return ptr->_is_data_ready;
                //     else return true;
                // });
                self->_written_body_len += bytes_transferred;
                if (!ec)
                {
                    LOG_ERROR("write error!, detail: {}", ec.what());
                }
                std::size_t len_tmp = self->_response._is_img ? self->_bytes_read : self->_response.getBodyLen();
                if (self->_written_body_len >= len_tmp)
                {
                    if (self->_written_body_len >= self->_response.getBodyLen())    //全部读完的情况
                    {
                        LOG_INFO("Write Body Finished");
                        LOG_INFO("HTTP Connection Close");
                        LOG_INFO("transfered bytes: {}", bytes_transferred);
                        self->_socket.shutdown(tcp::socket::shutdown_send, ec);
                        self->_deadline.cancel(); // 取消定时器
                        self->_cv.notify_all(); //将所有阻塞的线程唤醒，令其退出
                        //因为使用lambda表达式捕获的共享指针引用计数永久+1，不会被析构，所以要调用共享指针的析构函数，尽早释放掉内存
                        self.~shared_ptr();
                        return;
                    }
                    if (self->_response._is_img)
                    {
                        self->_body_sent = true;
                        self->_is_data_ready = false;
                        memcpy(self->_response.get_img_body(), '\0', 1024);    //清空缓冲区
                        self->_cv.notify_one();     //只有全部写完了才去通知读取图片的那便进行处理
                    }
                }
                else
                {
                    self->Handle_Write_Body();
                }
            }
        );
    }
    catch(const std::exception& e)
    {
        LOG_ERROR("ERROR OCCUER!: {}", e.what());
    }
    


}

void HttpConnection::HandleNotFound()
{
    _response.result(http_status::not_found);
    // _response.set(http::field::content_type, "text/plain");  //交由HandleReq()处理
    // beast::ostream(_response.body()) << "url not found\r\n";

    WriteResponse();
}

void HttpConnection::HandleSuccess()
{
    _response.result(http_status::ok);
    // _response.set(http::field::content_type, "application/json");    //交由HandleGetReq()来决定返回什么
    // _response.content_length(_response.body().size());
    WriteResponse();
    return;
}

tcp::socket &HttpConnection::GetSocket()
{
    return _socket;
}

void HttpConnection::PreParseGetParam()
{
    // 提取URI
    auto uri = _request.target();
    auto param_pos = uri.find('?');     // 查找'?'开始下标
    if (param_pos == std::string::npos) // 找不到'?'
    {
        _get_url = uri;
        std::cout << "url is " << _get_url << std::endl;
        size_t pos;
        if ((pos = _get_url.find("static/")) != std::string::npos) // 静态资源的请求处理
        {
            std::string res_path = _get_url.substr(pos + 7); // 截取/static/后面的路径
            res_path = UrlDecode(res_path);
            _get_url.erase(pos + 6, _get_url.size() - (pos + 6)); // 把/static后面的路径删掉s
            // std::cout << "-------------------------url is: " << _get_url << std::endl;
            _get_params["res_path"] = res_path; // 将路径存放到_get_params中
        }
        return;
    }
    // 提取参数
    // 先提取请求路径
    _get_url = uri.substr(0, param_pos++);
    // 提取请求参数
    //  std::string temp_str = uri.substr(param_pos);
    std::string temp_str = uri.substr(param_pos);
    std::string key;
    std::string val;
    size_t pos = 0;
    while ((pos = temp_str.find('&')) != std::string::npos)
    {
        auto pair = temp_str.substr(0, pos);
        size_t eq_pos = pair.find('=');
        if (eq_pos != std::string::npos)
        {
            key = UrlDecode(pair.substr(0, eq_pos)); // 假设有 url_decode 函数来处理URL解码
            val = UrlDecode(pair.substr(eq_pos + 1));
            _get_params[key] = val;
        }
        temp_str.erase(0, pos + 1);
    }
    // 处理最后一个参数对（如果没有 & 分隔符）
    if (!temp_str.empty())
    {
        size_t eq_pos = temp_str.find('=');
        if (eq_pos != std::string::npos)
        {
            key = UrlDecode(temp_str.substr(0, eq_pos));
            val = UrlDecode(temp_str.substr(eq_pos + 1));
            _get_params[key] = val;
        }
    }
}
